package cn.jasonone.at.util;

import java.lang.reflect.Field;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

import cn.jasonone.at.AutoTableProperties;
import cn.jasonone.at.annotation.Column;
import cn.jasonone.at.enums.JdbcType;
import cn.jasonone.at.exception.AutoTableException;
import cn.jasonone.at.model.ATField;
import cn.jasonone.at.model.ColumnInfo;
import lombok.extern.slf4j.Slf4j;
/**
 * 字段工厂
 * @author Jason
 *
 */
@Slf4j
public class ColumnFactory {

	private static AutoTableProperties properties;

	/**
	 * 设置配置对象
	 * @param properties 配置对象
	 */
	public static void setProperties(AutoTableProperties properties) {
		ColumnFactory.properties = properties;
	}

	/**
	 * 根据属性对象获取字段信息
	 * @param dbType 数据库类型
	 * @param field 属性对象
	 * @return 列信息
	 */
	public static ColumnInfo getColumnInfo(String dbType, ATField field) {
		ColumnInfo columnInfo = new ColumnInfo();
		Column column = field.getDeclaredAnnotation(Column.class);
		columnInfo.setAutoincrement(column.autoincrement());
		columnInfo.setColumnName(AnnotationUtil.getValue(column, "name", field.getName()));
		columnInfo.setComment(column.comment());
		columnInfo.setLength(column.length());
		columnInfo.setDecimalDigit(column.decimalDigit());
		columnInfo.setCatalog(properties.getCatalog());
		// 获取字段对应的Jdbc类型
		columnInfo.setDataType(getType(field));
		columnInfo.setType(getJdbcType(dbType, columnInfo));
		columnInfo.setPrimaryKey(column.primaryKey());
		columnInfo.setNullable(!column.notNull());
		columnInfo.setDefaultValue(column.defaultValue());
		return columnInfo;
	}

	/**
	 * 根据JdbcType获取实际的数据库的数据类型
	 * 
	 * @param dataType 数据库类型
	 * @return 数据类型
	 */
	private static String getJdbcType(String dbType, ColumnInfo columnInfo) {
		Map<String, Map<JdbcType, String>> jdbcTypes = properties.getJdbcTypes();
		if (jdbcTypes.containsKey(dbType)) {
			Map<JdbcType, String> types = jdbcTypes.get(dbType);
			JdbcType jdbcType = JdbcType.toJdbcType(columnInfo.getDataType());
			if (types.containsKey(jdbcType)) {
				String type = types.get(jdbcType);
				Map<String, Object> context = new HashMap<String, Object>(2);
				context.put("length", columnInfo.getLength());
				context.put("decimal", columnInfo.getDecimalDigit());
				return SqlUtil.parseSql(type, context);
			}else {
				log.warn("类型[{}]的映射配置不存在,将使用默认配置:{}",jdbcType.toString(),jdbcType.toString().toLowerCase());
				return jdbcType.toString().toLowerCase();
			}
		}
		throw new AutoTableException("对应数据库的类型映射不存在,请检查${auto-table.jdbc-types}配置中是否存在数据库[" + dbType + "]的映射配置");
	}

	/**
	 * 获取JdbcType类型
	 * 
	 * @param column 列注解
	 * @return {@link Types 数据类型}
	 */
	private static int getType(ATField field) {
		Column column = field.getDeclaredAnnotation(Column.class);
		Map<Class<?>, JdbcType> javaTypes = properties.getJavaTypes();
		if (JdbcType.AUTO == column.type()) {
			// 查找Java类映射匹配
			if (javaTypes.containsKey(field.getType())) {
				return javaTypes.get(field.getType()).getType();
			} else {
				throw new AutoTableException("数据类型映射错误:" + field.getType());
			}
		}
		return column.type().getType();
	}
}
